package server

import (
	"dag2.0/gat1400-proxy/cache"
	"dag2.0/gat1400-proxy/context"
	"dag2.0/gat1400-proxy/db"
	"dag2.0/gat1400-proxy/logger"
	"dag2.0/gat1400-proxy/model"
	"dag2.0/gat1400-proxy/model/constant"
	"dag2.0/gat1400-proxy/util"
	"dag2.0/gat1400-proxy/util/times"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/asaskevich/govalidator"
	jsoniter "github.com/json-iterator/go"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	URM_GET_TOLLAGTE  = "http://%s/api/tollgate/getCompriseEqByParam"
	URM_GET_EQUIPMENT = "http://%s/api/equipment/selectByParam"
	URM_GET_ORG       = "http://%s/api/organization/tree_posterity"   //查询跟组织
	URM_GETORG_BYCODE = "http://%s/api/organization/org_detail/%d/%s" //通过id与类型获取设备 {orgType}/{orgId}
	URM_ADD_ORG       = "http://%s/api/organization/batchAdd"         //增加组织
	URM_ADD_TOLLGATE  = "http://%s/api/tollgate/batchAddCompriseLane" //批量添加卡口接口
	URM_ADD_EQUIPMENT = "http://%s/api/equipment/batchAllAdd"         //批量添加采集设备接口
	ORG_DEVICE        = 1
	ORG_TOLLGATE      = 2
	SUBSCRIBLE_URL    = "http://%s:%s/VIID/Subscribes"
	URL_VEHICLE       = "http://%s/VIID/MotorVehicles"
)

var workFunctionMap = map[string]int{
	//1、 车辆卡口； 2、 人员卡口；3、 微卡口； 4、 特征摄像机；5、 普通监控；6、高空瞭望摄像机；
	// 7、人体卡口；8、门禁点；9、探针；10、电子围栏；11、RFID事件采集设备；12电子车牌采集设备；99其他， 多选各参数以“ /” 分隔
	"1": 1, //车辆
	"2": 2, //人员
	"7": 4, //人体
	//"FUNCTION_NONMOTOR": 16, //
	"5": 8, //
	//"FUNCTION_GPS":      32,
	"11": 64,
	//"FUNCTION_WIFI":     128,
}
var EQ_TYPE_MAP = map[int]int{
	/*
		key ://1、车辆卡口； 2、人员卡口；3、微卡口； 4、特征摄像机；5、普通监控；6、高空瞭望摄像机；7、人体卡口；8、门禁点；9、探针；10、电子围栏；11、RFID事件采集设备；12电子车牌采集设备；99其他， 多选各参数以“ /” 分隔
		value ://1摄像机,2车辆卡口,3WIFI设备,4电子围栏,5RIFD设备,6定位设备，7高空相机，11人脸抓拍机,13监视器，14微卡, 15卡口设备类型
	*/
	constant.GAT1400_FUNCTION_TYPE_VEHICLE:     constant.URM_EQ_TYPE_VEHICLETG,
	constant.GAT1400_FUNCTION_TYPE_HUMAN:       constant.URM_EQ_TYPE_FACEEQ,
	constant.GAT1400_FUNCTION_TYPE_MICRO:       constant.URM_EQ_TYPE_MICRO,
	constant.GAT1400_FUNCTION_TYPE_FEATURES:    constant.URM_EQ_TYPE_MICRO,
	constant.GAT1400_FUNCTION_TYPE_MONITOR:     constant.URM_EQ_TYPE_VEDIO,
	constant.GAT1400_FUNCTION_TYPE_HIGSKY:      constant.URM_EQ_TYPE_HIGSKY,
	constant.GAT1400_FUNCTION_TYPE_BODY:        constant.URM_EQ_TYPE_MICRO,
	constant.GAT1400_FUNCTION_TYPE_ACCESS:      constant.URM_EQ_TYPE_MICRO,
	constant.GAT1400_FUNCTION_TYPE_WIFI:        constant.URM_EQ_TYPE_WIFI,
	constant.GAT1400_FUNCTION_TYPE_BASESTATION: constant.URM_EQ_TYPE_BASESTATION,
	constant.GAT1400_FUNCTION_TYPE_RFID:        constant.URM_EQ_TYPE_RFID,
	constant.GAT1400_FUNCTION_TYPE__PLATE:      constant.URM_EQ_TYPE_MICRO,
}

func Subscribe() {
	go func() {
		for {
			//订阅任务
			if cache.GetIns().SubscribeTasks.Len() > 0 {
				SubscribeAction()
			}
			time.Sleep(time.Second * time.Duration(30))
		}
	}()

}

func SubscribeAction() {

	cache.GetIns().SubscribeTasks.Range(func(key string, value interface{}) (shouldContinue bool) {
		if _, ok := value.(*model.SubscribeLib); !ok {
			logger.LOG_ERROR(fmt.Sprintf("类型转换错误，需要*model.SubscribeManagerEx 类型，类型为:%T", value))
			return true
		}
		subscribeLib := value.(*model.SubscribeLib)

		if _, ok := cache.GetIns().SubscribeManagers.Load(subscribeLib.ManagerID); !ok {
			return true
		}

		managerInterFace, _ := cache.GetIns().SubscribeManagers.Load(subscribeLib.ManagerID)
		manager := managerInterFace.(*model.SubscribeManagerEx)
		//只处理作为上级的订阅
		if manager.ManagerType != constant.MANAGER_DOWN {
			return true
		}
		//已删除的订阅
		if subscribeLib.OperateType == -1 {
			_ = unSubscribe(subscribeLib)
			return true
		}
		//已完成订阅或已取消的订阅
		if subscribeLib.SubscribeStatus == 99 || subscribeLib.OperateType == 1 {
			return true
		}
		resultImageDeclare := context.GetInt("gat1400.ResultImageDeclare")

		switch subscribeLib.SubscribeDetail {
		//采集设备
		case constant.EQUIPMENT_LIST, constant.EQUIPMENT_STATUS:
			//创建组织
			//0行政区划分组(系统分组)，1采集设备分组(系统分组)，2卡口分组(系统分组)，3及以上为业务分组……不限以上
			e := CreatRootOrg(manager.ManagerID, ORG_DEVICE, manager.ManagerName)
			if e != nil {
				logger.LOG_ERROR("创建组织失败", e)
				return true
			}
			subscribeLib.ResultImageDeclare = "-1"
			//暂时写死为视图库
			subscribeLib.ResourceClass = 4
			//卡口
		case constant.TOLLGATE_LIST, constant.SINGLE_TOLLGATE_INFO, constant.HIK_ILLEGAL:
			e := CreatRootOrg(manager.ManagerID, ORG_TOLLGATE, manager.ManagerName)
			if e != nil {
				logger.LOG_ERROR("创建组织失败", e)
				return true
			}
			subscribeLib.ResultImageDeclare = "-1"
			if subscribeLib.SubscribeDetail == constant.HIK_ILLEGAL {
				subscribeLib.Subscribe.ProtocolType = 1
			} else {
				subscribeLib.Subscribe.ProtocolType = 0
			}
			//暂时写死为卡口
			subscribeLib.ResourceClass = 0
			//车道
		case constant.LAND_LIST, constant.SINGLE_LAND_INFO:
			e := CreatRootOrg(manager.ManagerID, ORG_TOLLGATE, manager.ManagerName)
			if e != nil {
				logger.LOG_ERROR("创建组织失败", e)
				return true
			}
			subscribeLib.ResultImageDeclare = "-1"
			subscribeLib.Subscribe.ProtocolType = 0
			//暂时写死为视图库
			subscribeLib.ResourceClass = 4
		case constant.PERSON_INFO:
			if resultImageDeclare == 1 {
				subscribeLib.ResultImageDeclare = "14"
			} else if resultImageDeclare == 2 {
				subscribeLib.ResultImageDeclare = "10"
			} else if resultImageDeclare == 3 {
				subscribeLib.ResultImageDeclare = "14,10"
			}
			if subscribeLib.ResultImageDeclare == "" {
				subscribeLib.ResultImageDeclare = "-1"
			}
			//subscribeLib.ResultImageDeclare = "10"
			subscribeLib.Subscribe.ProtocolType = 0

			//暂时写死为视图库
			subscribeLib.ResourceClass = 4
		case constant.FACE_INFO:
			if resultImageDeclare == 1 {
				subscribeLib.ResultImageDeclare = "14"
			} else if resultImageDeclare == 2 {
				subscribeLib.ResultImageDeclare = "11"
			} else if resultImageDeclare == 3 {
				subscribeLib.ResultImageDeclare = "14,11"
			}
			if subscribeLib.ResultImageDeclare == "" {
				subscribeLib.ResultImageDeclare = "-1"
			}
			subscribeLib.Subscribe.ProtocolType = 0

			//subscribeLib.ResultImageDeclare = "11"
			//暂时写死为视图库
			subscribeLib.ResourceClass = 4
		case constant.VEHICLE_INFO:
			if resultImageDeclare == 1 {
				subscribeLib.ResultImageDeclare = "01"
			} else if resultImageDeclare == 2 {
				subscribeLib.ResultImageDeclare = "02"
			} else if resultImageDeclare == 3 {
				subscribeLib.ResultImageDeclare = "01,02"
			}
			if subscribeLib.ResultImageDeclare == "" {
				subscribeLib.ResultImageDeclare = "-1"
			}
			subscribeLib.Subscribe.ProtocolType = 0

			//subscribeLib.ResultImageDeclare = "02"
			//暂时写死为视图库
			subscribeLib.ResourceClass = 4
		case constant.NOMOTOR_INFO:
			if resultImageDeclare == 1 {
				subscribeLib.ResultImageDeclare = "14"
			} else if resultImageDeclare == 2 {
				subscribeLib.ResultImageDeclare = "12"
			} else if resultImageDeclare == 3 {
				subscribeLib.ResultImageDeclare = "14,12"
			}
			if subscribeLib.ResultImageDeclare == "" {
				subscribeLib.ResultImageDeclare = "-1"
			}
			subscribeLib.Subscribe.ProtocolType = 0

			//subscribeLib.ResultImageDeclare = "12"
			//暂时写死为视图库
			subscribeLib.ResourceClass = 4
		}
		//处理时间格式
		if subscribeLib.BeginTime != "" {
			subscribeLib.BeginTime = times.Time2StrF(times.Str2Time(subscribeLib.BeginTime), times.DateFormatNoSpan)
		}
		if subscribeLib.EndTime != "" {
			subscribeLib.EndTime = times.Time2StrF(times.Str2Time(subscribeLib.EndTime), times.DateFormatNoSpan)
		}

		subscribeLib.ResultFeatureDeclare = -1
		//发送订阅请求
		subscribe := make([]*model.Subscribe, 0)
		subscribe = append(subscribe, subscribeLib.Subscribe)
		subscribeModel := &model.SubscribeModel{SubscribeListObject: &model.SubscribeListObject{SubscribeObject: subscribe}}
		respBytes, _, _, e := util.Request(fmt.Sprintf(SUBSCRIBLE_URL, manager.ManagerIp, manager.ManagerPort), http.MethodPost, map[string]string{
			"User-Identify": manager.SelfManagerID,
			"Content-Type":  "application/VIID+JSON",
		}, subscribeModel, nil)
		if e != nil {
			logger.LOG_ERROR("发送订阅失败", e)
			//  失败详情入库
			_ = FlushSubscribeStatusCache(subscribeLib, "-1", "订阅失败."+e.Error())
			return true
		}
		response := model.AnalyzeRsponseContent(respBytes)
		resJson, _ := jsoniter.Marshal(response)
		//失败
		if response == nil || len(response.ResponseStatusListObject.ResponseStatusObject) <= 0 ||
			response.ResponseStatusListObject.ResponseStatusObject[0] == nil ||
			response.ResponseStatusListObject.ResponseStatusObject[0].StatusCode != model.OK {
			resData := util.BytesString(resJson)
			logger.LOG_ERROR("订阅失败 ", resData) //等待下次重新发送
			_ = FlushSubscribeStatusCache(subscribeLib, "-1", "订阅失败."+resData)
			return true
		}
		logger.LOG_WARN("发送订阅成功，返回数据为：", util.BytesString(resJson))
		//更新缓存
		_ = FlushSubscribeStatusCache(subscribeLib, "99", "")
		return true
	})
}
func unSubscribe(subscribelib *model.SubscribeLib) error {
	managerInterFace, _ := cache.GetIns().SubscribeManagers.Load(subscribelib.ManagerID)
	manager := managerInterFace.(*model.SubscribeManagerEx)
	subscribeObject := &model.SubscribeObject{SubscribeObject: &model.Subscribe{
		SubscribeID:           subscribelib.SubscribeID,
		Title:                 subscribelib.Title,
		SubscribeDetail:       subscribelib.SubscribeDetail,
		ResourceURI:           subscribelib.ResourceURI,
		ApplicantName:         subscribelib.ApplicantName,
		ApplicantOrg:          subscribelib.ApplicantOrg,
		BeginTime:             subscribelib.BeginTime,
		EndTime:               subscribelib.EndTime,
		ReceiveAddr:           subscribelib.ReceiveAddr,
		ReportInterval:        subscribelib.ReportInterval,
		Reason:                subscribelib.Reason,
		OperateType:           1,
		SubscribeStatus:       1,
		SubscribeCancelOrg:    subscribelib.SubscribeCancelOrg,
		SubscribeCancelPerson: subscribelib.SubscribeCancelPerson,
		CancelTime:            subscribelib.CancelTime,
		CancelReason:          subscribelib.CancelReason,
		ResourceClass:         subscribelib.ResourceClass,
		ResultFeatureDeclare:  -1,
		ResultImageDeclare:    subscribelib.ResultImageDeclare,
		TabID:                 subscribelib.TabID,
	}}
	//发送订阅请求
	//subscribeModel := &model.SubscribeModel{SubscribeListObject: &model.SubscribeListObject{SubscribeObject: subscribe}}
	respBytes, _, _, e := util.Request(fmt.Sprintf(CANCELSUBSCRIBLE_URL, manager.ManagerIp, manager.ManagerPort, subscribelib.SubscribeID),
		http.MethodPut, map[string]string{
			"User-Identify": manager.SelfManagerID,
			"Content-Type":  "application/VIID+JSON",
		}, subscribeObject, nil)
	if e != nil {
		logger.LOG_ERROR("取消订阅失败", e)
		return errors.New("取消订阅失败")
	}
	response := model.AnalyzeRsponseContent(respBytes)
	resJson, _ := jsoniter.Marshal(response)
	//失败
	if response == nil || len(response.ResponseStatusListObject.ResponseStatusObject) <= 0 ||
		response.ResponseStatusListObject.ResponseStatusObject[0] == nil ||
		response.ResponseStatusListObject.ResponseStatusObject[0].StatusCode != model.OK {
		logger.LOG_ERROR("取消订阅失败 ", util.BytesString(resJson))
		return errors.New("取消订阅失败")
	}
	logger.LOG_WARN("取消订阅成功，返回数据为：", util.BytesString(resJson))
	de := db.DeleteSubcribeById(subscribelib.SubscribeID)
	if de != nil {
		return errors.New("删除订阅失败")
	}
	//删除缓存中的订阅任务
	cache.GetIns().SubscribeTasks.Delete(subscribelib.SubscribeID)
	return nil
}
func DealResourceNotification(subscribeNotificationModel *model.SubscribeNotificationModel, viewId string) error {

	//****订阅卡口---> 订阅采集设备 ---> 订阅车道（保证每次订阅只会有一种设备类型）
	//1.采集设备，
	//2.卡口
	//3.根据车道关联的卡口与设备:查询urm中卡口与采集设备，将车道与采集设备封装到卡口内，若未查询到，丢弃，下次重复订阅
	var urmDevices = make([]*model.URMEquipment, 0)                  //采集设备
	var urmTollgate = make([]*model.URMTollgate, 0)                  //卡口
	var urmTollgateWithLane = make(map[string]*model.URMTollgate, 0) // 卡口带车道的集合
	var err error
	subscribeNotificationObject := subscribeNotificationModel.SubscribeNotificationListObject.SubscribeNotificationObject
	for _, subscribeNotification := range subscribeNotificationObject {
		bytes, _ := jsoniter.Marshal(subscribeNotification)
		if logger.IsDebug() {
			logger.LOG_DEBUG("通知结构为:", util.BytesString(bytes))
		}
		//采集设备处理
		if subscribeNotification.DeviceList != nil && subscribeNotification.DeviceList.APEObject != nil {
			urmDevices = append(urmDevices, transformApes(subscribeNotification.DeviceList.APEObject, viewId)...)
		}
		//卡口
		if subscribeNotification.TollgateObjectList != nil && subscribeNotification.TollgateObjectList.TollgateObject != nil {
			//urmTollgate = append(urmTollgate, transformTollgetes(subscribeNotification.TollgateObjectList.TollgateObject, viewId)...)
			//urmTollgate, err = dealTollgateList(subscribeNotification.TollgateObjectList.TollgateObject, viewId)
			//批量增加卡口是是追加不是覆盖
			list, err := dealTollgateList(subscribeNotification.TollgateObjectList.TollgateObject, viewId)
			if err != nil {
				logger.LOG_ERROR("处理失败")
				return err
			}
			urmTollgate = append(urmTollgate, list...)
		}
		//车道
		if subscribeNotification.LaneObjectList != nil && subscribeNotification.LaneObjectList.LaneObject != nil {
			urmTollgateWithLane, err = dealLane(subscribeNotification.LaneObjectList.LaneObject)
			if err != nil {
				logger.LOG_ERROR("处理失败")
				return err
			}
		}
		//海康过和和违法
		if subscribeNotification.MotorVehicleObjectList != nil && subscribeNotification.MotorVehicleObjectList.MotorVehicleObject != nil {
			//motorVehicles := subscribeNotification.MotorVehicleObjectList
			//subscribeNotification.MotorVehicleListObject = subscribeNotification.MotorVehicleObjectList
			wrapper := map[string]interface{}{
				"MotorVehicleListObject": subscribeNotification.MotorVehicleObjectList,
			}
			//motorVehicles := subscribeNotification.MotorVehicleListObject
			id := subscribeNotification.MotorVehicleObjectList.MotorVehicleObject[0].TollgateID
			jsonBytes, _ := json.Marshal(wrapper)
			_, _, _, err := util.RequestVIID(fmt.Sprintf(URL_VEHICLE, os.Getenv("VIID_IP_PORT")), http.MethodPost, map[string]string{
				"User-Identify": id,
				"Content-Type":  "application/VIID+JSON",
			}, jsonBytes, nil)
			if err != nil {
				logger.LOG_ERROR("发送车辆信息至VIID失败", err)
				return err
			}

		}
	}
	if len(urmDevices) > 0 {
		//调用urm接口保存采集设备
		bytes, _, _, e := util.Request(fmt.Sprintf(URM_ADD_EQUIPMENT, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
			"Content-Type": "application/json",
		}, urmDevices, nil)
		if e != nil {
			logger.LOG_ERROR("保存采集设备至urm失败", e)
			return e
		}
		if _, e := analyzeUrmRsponse(bytes); e != nil {
			return e
		}
		logger.LOG_WARN("保存采集设备至urm成功,采集设备个数为 ：", len(urmDevices))
	}
	if len(urmTollgate) > 0 {
		//调用urm接口保存卡口
		bytes, _, _, e := util.Request(fmt.Sprintf(URM_ADD_TOLLGATE, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
			"Content-Type": "application/json",
		}, urmTollgate, nil)
		if e != nil {
			logger.LOG_ERROR("保存卡口设备至urm失败", e)
			return e
		}
		if _, e := analyzeUrmRsponse(bytes); e != nil {
			return e
		}
		logger.LOG_WARN("保存卡口至urm成功,卡口个数为 ：", len(urmTollgate))
	}
	if len(urmTollgateWithLane) > 0 {
		var urmTollgate = make([]*model.URMTollgate, 0) //卡口
		//调用urm接口保存带有车道映射关系的卡口
		for _, tollgate := range urmTollgateWithLane {
			urmTollgate = append(urmTollgate, tollgate)
		}
		bytes, _, _, e := util.Request(fmt.Sprintf(URM_ADD_TOLLGATE, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
			"Content-Type": "application/json",
		}, urmTollgate, nil)
		if e != nil {
			logger.LOG_ERROR("保存卡口下的设备至urm失败", e)
			return e
		}
		if _, e := analyzeUrmRsponse(bytes); e != nil {
			return e
		}
		logger.LOG_WARN("保存卡口设备至urm成功,卡口设备个数为 ：", len(urmDevices))
	}
	return nil
}
func analyzeUrmRsponse(bytes []byte) (*UrmResp, error) {
	res := &UrmResp{}
	e := jsoniter.Unmarshal(bytes, res)
	if e != nil {
		logger.LOG_ERROR("解析json 失败", e)
		return nil, e
	}
	if res.Code != 200 {
		logger.LOG_ERROR("调用urm接口失败，返回码为 : ", res.Code)
		return nil, errors.New(fmt.Sprintf("调用urm接口，返回码为 ： %d", res.Code))
	}
	return res, nil
}

type UrmResp struct {
	Code         int                 `json:"code"`
	ErrorMessage string              `json:"errorMessage"`
	Data         jsoniter.RawMessage `json:"data"`
}

func buildLane(lane *model.Lane) *model.URMLane {
	return &model.URMLane{
		ChannelNo:   "",
		EquipmentID: lane.ApeID,
		ID:          lane.TollgateID + strconv.Itoa(lane.LaneId),
		LaneNo:      lane.LaneNo,
		Name:        lane.Name,
		ThirdID:     lane.ApeID,
		TollgateID_: lane.TollgateID,
	}
}
func convStringToInt(str string, defaultValue int) int {
	if len(str) > 0 {
		value, e := strconv.Atoi(str)
		if e == nil {
			return value
		}
	}
	return defaultValue
}
func dealLane(lanes []*model.Lane) (map[string]*model.URMTollgate, error) {
	//根据车道中的卡口编号，找到所已有的卡口信息，先从内存中找，若无法找到去库里查，库里也不存在的，丢弃并打印日志
	tollgateIds := make([]string, 0) //卡口id集合
	apeIds := make([]string, 0)      //
	for _, lane := range lanes {
		if lane.TollgateID != "" {
			tollgateIds = append(tollgateIds, lane.TollgateID)
		}
		if lane.ApeID != "" {
			apeIds = append(apeIds, lane.ApeID)
		}
	}
	//调用urm接口,查询卡口
	var tollgates = make([]*model.URMTollgate, 0)
	var tgMaps = make(map[string]*model.URMTollgate, 0)
	_, _, _, err := util.Request(fmt.Sprintf(URM_GET_TOLLAGTE, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
		"Content-Type": "application/json",
	}, map[string]interface{}{
		"ids": tollgateIds,
	}, &tollgates)
	if err != nil {
		logger.LOG_WARN("get urm tollgate error  ", err)
		return nil, err
	}
	for _, tollgate := range tollgates {
		tgMaps[tollgate.ID] = tollgate
	}
	//调用urm接口,查询采集设备
	var equipments = make([]*model.URMEquipment, 0)
	var eqMaps = make(map[string]*model.URMEquipment, 0)
	_, _, _, err = util.Request(fmt.Sprintf(URM_GET_EQUIPMENT, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
		"Content-Type": "application/json",
	}, map[string]interface{}{
		"ids": apeIds,
	}, &equipments)
	if err != nil {
		logger.LOG_WARN("get urm equipment error  ", err)
		return nil, err
	}
	for _, equipment := range equipments {
		eqMaps[equipment.ID] = equipment
	}
	for _, lane := range lanes {
		//若无卡口关联，则直接放弃处理
		if lane.TollgateID == "" {
			logger.LOG_WARN("此车道无关联卡口, ", lane.Name)
			continue
		}
		if _, ok := tgMaps[lane.TollgateID]; !ok {
			logger.LOG_WARN("此车道关联的卡口未在urm中找到,车道为:  ", lane.Name, "关联的卡口为 ：", lane.TollgateID)
			continue
		}
		tg := tgMaps[lane.TollgateID]
		if tg.LaneList == nil {
			tg.LaneList = make([]*model.URMLane, 0)
		}
		if tg.EquipmentList == nil {
			tg.EquipmentList = make([]*model.URMTollgateEquipment, 0)
		}
		tg.LaneList = append(tg.LaneList, buildLane(lane))
		//构建采集设备
		if lane.ApeID == "" {
			logger.LOG_WARN("此车道无关联的卡口设备, 车道为 : ", lane.Name)
			continue
		}
		//未找到关联的采集设备
		if _, ok := eqMaps[lane.ApeID]; !ok {
			logger.LOG_WARN("此车道未找到关联的卡口下的采集设备, 车道为 : ", lane.Name, "关联的卡口设备为 :  ", lane.ApeID)
			continue
		}
		tg.EquipmentList = append(tg.EquipmentList, buildTollgateEquipment(eqMaps[lane.ApeID]))
	}

	return tgMaps, nil
}

func dealTollgateList(tollgates []*model.Tollgate, viewId string) ([]*model.URMTollgate, error) {
	var urmTollgates = make([]*model.URMTollgate, 0)
	if len(tollgates) == 0 {
		return urmTollgates, nil
	}
	//先查后插,以免覆盖原有卡口设备与车道信息
	var tollgateIds = make([]string, 0)
	for _, tollgate := range tollgates {
		tollgateIds = append(tollgateIds, tollgate.TollgateID)
	}
	var hasTollgates = make([]*model.URMTollgate, 0)
	var hasTollgateMap = make(map[string]*model.URMTollgate, 0)
	_, _, _, e := util.Request(fmt.Sprintf(URM_GET_TOLLAGTE, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
		"Content-Type": "application/json",
	}, map[string]interface{}{
		"ids": tollgateIds,
	}, &hasTollgates)
	if e != nil {
		logger.LOG_ERROR("request urm tollgate error", e)
		return nil, errors.New("获取卡口信息失败 ")
	}
	for _, tollgate := range hasTollgates {
		hasTollgateMap[tollgate.ID] = tollgate
	}
	//对于已有卡口，只更新基本信息，车道与卡口设备不更新
	for _, tollgate := range tollgates {
		if oldUrmTollgate, ok := hasTollgateMap[tollgate.TollgateID]; ok {
			newTollgate := buildUrmTollgate(tollgate, viewId)
			newTollgate.EquipmentList = oldUrmTollgate.EquipmentList
			newTollgate.LaneList = oldUrmTollgate.LaneList
			newTollgate.LaneNum = oldUrmTollgate.LaneNum
			urmTollgates = append(urmTollgates, newTollgate)
			continue
		}
		urmTollgates = append(urmTollgates, buildUrmTollgate(tollgate, viewId))
	}
	return urmTollgates, nil
}

func buildUrmTollgate(tollgate *model.Tollgate, viewId string) *model.URMTollgate {
	return &model.URMTollgate{
		DataType:   0,
		GbID:       tollgate.TollgateID,
		ID:         tollgate.TollgateID,
		Name:       tollgate.Name,
		PlatformID: "",
		RegionCode: tollgate.OrgCode,
		ThirdID:    tollgate.TollgateID,
		Longitude:  tollgate.Longitude,
		Latitude:   tollgate.Latitude,
		PlaceCode:  tollgate.PlaceCode,
		OrgCode:    viewId,
		Status:     1,
		Usage:      tollgate.TollgateUsage,
	}
}

func buildUrmEq(ape *model.APE, viewId string) *model.URMEquipment {
	return &model.URMEquipment{
		ID:                ape.ApeID,
		GbID:              ape.ApeID,
		Name:              ape.Name,
		DataType:          0,
		IPAddr:            ape.IPAddr,
		Ipv6Addr:          ape.IPV6Addr,
		MacAddress:        "",
		Manufacturer:      "",
		Model:             ape.Model,
		Password:          ape.Password,
		PlatformID:        "",
		Port:              ape.Port,
		RegionCode:        "",
		ThirdID:           ape.ApeID,
		UserName:          ape.UserId,
		Longitude:         ape.Longitude,
		Latitude:          ape.Latitude,
		PlaceCode:         ape.PlaceCode,
		Place:             ape.Place,
		OrgCode:           viewId,
		CameraChannelList: nil,
		ComponentAddr:     "",
		ComponentPort:     0,
	}
}

func transformTollgetes(tollgates []*model.Tollgate, viewId string) (urmTollgates []*model.URMTollgate) {
	if len(tollgates) < 1 {
		return make([]*model.URMTollgate, 0)
	}

	for _, tollgate := range tollgates {
		urmTollgates = append(urmTollgates, &model.URMTollgate{
			DataType:      0,
			EquipmentList: nil,
			GbID:          tollgate.TollgateID,
			ID:            tollgate.TollgateID,
			LaneList:      nil,
			LaneNum:       0,
			Name:          tollgate.Name,
			PlatformID:    "",
			RegionCode:    tollgate.PlaceCode,
			ThirdID:       tollgate.TollgateID,
			Longitude:     tollgate.Longitude,
			Latitude:      tollgate.Latitude,
			PlaceCode:     tollgate.PlaceCode,
			OrgCode:       viewId,
			Status:        1,
			Usage:         tollgate.TollgateUsage,
		})
	}
	return
}

func transformApes(apes []*model.APE, viewId string) (urmDevices []*model.URMEquipment) {
	if len(apes) < 1 {
		return make([]*model.URMEquipment, 0)
	}
	for _, ape := range apes {
		if len(ape.UserId) > 36 {
			ape.UserId = ""
		}
		if len(ape.Password) > 36 {
			ape.Password = ""
		}
		//默认
		var Type = constant.URM_EQ_TYPE_FACEEQ
		split := strings.Split(ape.FunctionType, "/")
		var functionType = 0
		for i := range split {
			s := split[i]
			if value, ok := workFunctionMap[s]; ok {
				functionType = functionType ^ value
			}
		}
		if functionType == 0 {
			functionType = constant.URM_EQ_TYPE_VEHICLETG
		}
		if len(split) == 1 {
			function, _ := strconv.Atoi(ape.FunctionType)
			if eqType, ok := EQ_TYPE_MAP[function]; ok {
				Type = eqType
			}
		} else if len(split) > 1 {
			//国标中含有多个功能类型，urm的设备类型设置成微卡口
			Type = constant.URM_EQ_TYPE_MICRO
		}
		//若含有摄像功能，类型改为摄像机
		for _, s := range split {
			if s == strconv.Itoa(constant.GAT1400_FUNCTION_TYPE_MONITOR) {
				Type = constant.URM_EQ_TYPE_VEDIO
			}
		}
		//卡口设备
		if ape.TollgateID != "" {
			Type = constant.URM_EQ_TYPE_EQOFTG
		}
		logger.LOG_INFO("functionType :", functionType)
		urmDevices = append(urmDevices, &model.URMEquipment{
			ID:                ape.ApeID,
			GbID:              ape.ApeID,
			Name:              ape.Name,
			DataType:          0,
			IPAddr:            ape.IPAddr,
			Ipv6Addr:          ape.IPV6Addr,
			MacAddress:        "",
			Model:             ape.Model,
			Password:          ape.Password,
			PlatformID:        "",
			Port:              ape.Port,
			RegionCode:        ape.PlaceCode, //行政区划
			ThirdID:           ape.ApeID,
			UserName:          ape.UserId,
			Longitude:         ape.Longitude,
			Latitude:          ape.Latitude,
			PlaceCode:         ape.PlaceCode, //安装地点行政区划
			Place:             "",
			OrgCode:           viewId,
			CameraChannelList: nil,
			ComponentAddr:     "",
			ComponentPort:     0,
			Type:              Type, //1摄像机,2车辆卡口,3WIFI设备,4电子围栏,5RFID设备,6定位设备，7高空相机，11人脸抓拍机,13监视器，14微卡, 15卡口设备类型'
			WorkFunction:      functionType,
			Manufacturer:      ape.AreaType,
			MonitorAreaDesc:   ape.PassDirection,
			LinkMan:           ape.FunctionType,
			OwnerApsId:        ape.MonitorDirection,
		})
	}
	return
}
func isIllegalApe(ape *model.APE) error {
	_, err := govalidator.ValidateStruct(ape)

	return err
}
func removeRepByMap(slc []string) []string {
	result := []string{}         //存放返回的不重复切片
	tempMap := map[string]byte{} // 存放不重复主键
	for _, e := range slc {
		l := len(tempMap)
		tempMap[e] = 0 //当e存在于tempMap中时，再次添加是添加不进去的，，因为key不允许重复
		//如果上一行添加成功，那么长度发生变化且此时元素一定不重复
		if len(tempMap) != l { // 加入map后，map长度变化，则元素不重复
			result = append(result, e) //当元素不重复时，将元素添加到切片result中
		}
	}
	return result
}

func dealApeList(apes []*model.APE, viewId string) ([]*model.URMEquipment, []*model.URMTollgate) {
	if apes == nil || len(apes) < 1 {
		return nil, nil
	}
	var urmTollgates = make([]*model.URMTollgate, 0)
	var urmTollgateDevices = make([]*model.URMEquipment, 0)
	var apeObject = make([]*model.APE, 0)    //采集设备
	var tollgateApes = make([]*model.APE, 0) //卡口设备集合
	var tollgateIds = make([]string, 0)      //卡口id集合
	for _, ape := range apes {
		if ape.TollgateID == "" {
			apeObject = append(apeObject, ape)
		} else {
			tollgateApes = append(tollgateApes, ape)
			tollgateIds = append(tollgateIds, ape.TollgateID)
		}
	}
	tollgateIds = removeRepByMap(tollgateIds)      //id去重
	urmDevices := transformApes(apeObject, viewId) //采集设备
	//获取tollgate
	var urmTollgateMaps = make(map[string]*model.URMTollgate, 0)
	_, _, _, e := util.Request(fmt.Sprintf(URM_GET_TOLLAGTE, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
		"Content-Type": "application/json",
	}, map[string]interface{}{
		"ids": tollgateIds,
	}, &urmTollgates)
	if e != nil {
		logger.LOG_ERROR("获取urm卡口失败", e)
	}
	//获取已存在的tollgate
	for _, urmTollgate := range urmTollgates {
		urmTollgateMaps[urmTollgate.ID] = urmTollgate
	}
	for _, tollgateApe := range tollgateApes {
		if tollgate, ok := urmTollgateMaps[tollgateApe.TollgateID]; ok {
			//卡口内未存在卡口设备
			if tollgate.EquipmentList == nil || len(tollgate.EquipmentList) < 1 {
				equipments := make([]*model.URMTollgateEquipment, 0)
				equipments = append(equipments, buildUrmTollgateEquipment(tollgateApe))
				tollgate.EquipmentList = equipments
				continue
			}
			equipments := tollgate.EquipmentList
			for _, equipment := range equipments {
				//已包含此卡口设备，修改
				if tollgateApe.ApeID == equipment.ID {
					equipment = buildUrmTollgateEquipment(tollgateApe)
				} else { //未包含此卡口设备，添加
					equipments = append(equipments, buildUrmTollgateEquipment(tollgateApe))
				}
			}
		} else {
			urmTollgateDevices = append(urmTollgateDevices, buildUrmEq(tollgateApe, viewId))
			//不存在的 记录日志
			logger.LOG_WARN("此设备未查询到锁关联的tollgateId，设备国标id 为 : ", tollgateApe.ApeID, "关联卡口Id为 ： ", tollgateApe.TollgateID)
		}
	}
	return urmDevices, urmTollgates
}
func buildUrmTollgateEquipment(tollgateApe *model.APE) *model.URMTollgateEquipment {
	return &model.URMTollgateEquipment{
		GbID:                  tollgateApe.ApeID,
		ID:                    tollgateApe.ApeID,
		IPAddr:                tollgateApe.IPAddr,
		Manufacturer:          "",
		Model:                 tollgateApe.Model,
		Password:              tollgateApe.Password,
		Port:                  tollgateApe.Port,
		ThirdID:               tollgateApe.ApeID,
		TollgateEquipmentType: 0,
		UserName:              "",
		Type:                  15, //卡口设备类型
	}
}
func buildTollgateEquipment(eq *model.URMEquipment) *model.URMTollgateEquipment {
	return &model.URMTollgateEquipment{
		GbID:                  eq.ID,
		ID:                    eq.GbID,
		IPAddr:                eq.IPAddr,
		Manufacturer:          "",
		Model:                 eq.Model,
		Password:              eq.Password,
		Port:                  eq.Port,
		ThirdID:               eq.ThirdID,
		TollgateEquipmentType: 0,
		UserName:              eq.UserName,
		Type:                  15, //卡口设备类型
	}
}

func CreatOrg(parentId string, orgType int, viewName string, orgId string) error {
	bytes, _, _, e := util.Request(fmt.Sprintf(URM_GETORG_BYCODE, os.Getenv("URM_IP_PORT"), orgType, orgId), http.MethodGet, map[string]string{
		"Content-Type": "application/json",
	}, nil, nil)
	if e != nil {
		logger.LOG_ERROR("查询urm管辖机构组织失败", e)
		return e
	}
	resp, e := analyzeUrmRsponse(bytes)
	if e != nil || resp == nil {
		logger.LOG_ERROR("查询urm管辖机构组织失败", e)
		return e
	}
	orgConfig := make(map[string]string, 0)
	//存在此组织
	e = jsoniter.Unmarshal(resp.Data, &orgConfig)
	if e != nil {
		logger.LOG_DEBUG("创建组织，解析urm返回失败", e)
		return e
	}
	if len(orgConfig) > 0 {
		return nil
	}
	//创建组织
	var org = &model.URMOrg{
		Id:       orgId,
		Gbid:     orgId,
		ParentId: parentId,
		Name:     viewName,
		Type:     orgType,
	}
	var orgs = make([]*model.URMOrg, 0)
	orgs = append(orgs, org)
	bytes, _, _, e = util.Request(fmt.Sprintf(URM_ADD_ORG, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
		"Content-Type": "application/json",
	}, orgs, nil)
	if e != nil {
		logger.LOG_ERROR("创建urm管辖机构组织失败", e)
		return e
	}
	logger.LOG_WARN("创建urm返回消息体", string(bytes))
	resp, e = analyzeUrmRsponse(bytes)
	if e != nil {
		logger.LOG_ERROR("创建urm管辖机构组织失败", string(bytes))
		return e
	}
	logger.LOG_WARN("创建urm管辖机构组织成功")
	return nil
}

func CreatRootOrg(viewId string, orgType int, viewName string) error {
	//查询跟组织
	var parentId = "0"
	bytes, _, _, e := util.Request(fmt.Sprintf(URM_GET_ORG, os.Getenv("URM_IP_PORT")), http.MethodPost, map[string]string{
		"Content-Type": "application/json",
	}, map[string]interface{}{
		"orgType":  orgType,
		"nodeType": "1",
		"isAdmin":  true,
		"needColumns": []string{
			"parentId", "nodeType", "gbid",
		},
		"treeLevel": 0,
	}, nil)
	fmt.Println(string(bytes))
	resp, e := analyzeUrmRsponse(bytes)
	if e != nil || resp == nil {
		logger.LOG_ERROR("查询urm根组织失败", e)
		return e
	}
	if resp.Data != nil {
		rootOrgs := make([]map[string]interface{}, 0)
		e = jsoniter.Unmarshal(resp.Data, &rootOrgs)
		if e != nil {
			logger.LOG_ERROR("解析跟组织失败，解析urm返回失败", e)
			return e
		}
		if len(rootOrgs) == 0 {
			return errors.New("未含有根节点")
		}
		for _, rootOrg := range rootOrgs {
			if _, ok := rootOrg["parentId"]; !ok {
				continue
			}
			if orgId, ok := rootOrg["id"]; ok {
				parentId = orgId.(string)
			}
		}
	}
	return CreatOrg(parentId, orgType, viewName, viewId)
}
